home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2001 May / SGI Freeware 2001 May - Disc 3.iso / dist / fw_expect.idb / usr / freeware / bin / kibitz.z / kibitz
Text File  |  1999-01-26  |  11KB  |  407 lines

  1. #!/usr/freeware/bin/expect --
  2. # allow another user to share a shell (or other program) with you
  3. # See kibitz(1) man page for complete info.
  4. # Author: Don Libes, NIST
  5. # Date written: December 5, 1991
  6. # Date last editted: October 19, 1994
  7. # Version: 2.11
  8. exp_version -exit 5.0
  9.  
  10. # if environment variable "EXPECT_PROMPT" exists, it is taken as a regular
  11. # expression which matches the end of your login prompt (but does not other-
  12. # wise occur while logging in).
  13.  
  14. set prompt "(%|#|\\$) $"    ;# default prompt
  15. set noproc 0
  16. set tty ""            ;# default if no -tty flag
  17. set allow_escape 1        ;# allow escapes if true
  18. set escape_char \035        ;# control-right-bracket
  19. set escape_printable "^\]"
  20. set verbose 1            ;# if true, describe what kibitz is doing
  21.  
  22. set kibitz "kibitz"        ;# where kibitz lives if some unusual place.
  23.                 ;# this must end in "kibitz", but can have
  24.                 ;# things in front (like directory names).
  25. #set proxy "kibitz"        ;# uncomment and set if you want kibitz to use
  26.                 ;# some other account on remote systems
  27.  
  28. # The following code attempts to intuit whether cat buffers by default.
  29. # The -u flag is required on HPUX (8 and 9) and IBM AIX (3.2) systems.
  30. if [file exists $exp_exec_library/cat-buffers] {
  31.     set catflags "-u"
  32. } else {
  33.     set catflags ""
  34. }
  35. # If this fails, you can also force it by commenting in one of the following.
  36. # Or, you can use the -catu flag to the script.
  37. #set catflags ""
  38. #set catflags "-u"
  39.  
  40. # Some flags must be passed onto the remote kibitz process.  They are stored
  41. # in "kibitz_flags".  Currently, they include -tty and -silent.
  42. set kibitz_flags ""
  43.  
  44. while {[llength $argv]>0} {
  45.     set flag [lindex $argv 0]
  46.     switch -- $flag \
  47.     "-noproc" {
  48.         set noproc 1
  49.         set argv [lrange $argv 1 end]
  50.     } "-catu" {
  51.         set catflags "-u"
  52.         set argv [lrange $argv 1 end]
  53.     } "-tty" {
  54.         set tty [lindex $argv 1]
  55.         set argv [lrange $argv 2 end]
  56.         set kibitz_flags "$kibitz_flags -tty $tty"
  57.     } "-noescape" {
  58.         set allow_escape 0
  59.         set argv [lrange $argv 1 end]
  60.     } "-escape" {
  61.         set escape_char [lindex $argv 1]
  62.         set escape_printable $escape_char
  63.         set argv [lrange $argv 2 end]
  64.     } "-silent" {
  65.         set verbose 0
  66.         set argv [lrange $argv 1 end]
  67.         set kibitz_flags "$kibitz_flags -silent"
  68.     } "-proxy" {
  69.         set proxy [lindex $argv 1]
  70.         set argv [lrange $argv 2 end]
  71.     } default {
  72.         break
  73.     }
  74. }
  75.  
  76. if {([llength $argv]<1) && ($noproc==0)} {
  77.     send_user "usage: kibitz \[args] user \[program ...]\n"
  78.     send_user "   or: kibitz \[args] user@host \[program ...]\n"
  79.     exit
  80. }
  81.  
  82. log_user 0
  83. set timeout -1
  84.  
  85. set user [lindex $argv 0]
  86. if [string match -r $user] {
  87.     send_user "KRUN"    ;# this tells user_number 1 that we're running
  88.                 ;# and to prepare for possible error messages
  89.     set user_number 3
  90.     # need to check that it exists first!
  91.     set user [lindex $argv 1]
  92. } else {
  93.     set user_number [expr 1+(0==[string first - $user])]
  94. }
  95.  
  96. # at this point, user_number and user are correctly determined
  97. # User who originated kibitz session has user_number == 1 on local machine.
  98. # User who is responding to kibitz has user_number == 2.
  99. # User who originated kibitz session has user_number == 3 on remote machine.
  100.  
  101. # user 1 invokes kibitz as "kibitz user[@host]"
  102. # user 2 invokes kibitz as "kibitz -####" (some pid).
  103. # user 3 invokes kibitz as "kibitz -r user".
  104.  
  105. # uncomment for debugging: leaves each user's session in a file: 1, 2 or 3
  106. #exec rm -f $user_number
  107. #exp_internal -f $user_number 0
  108.  
  109. set user2_islocal 1    ;# assume local at first
  110.  
  111. # later move inside following if $user_number == 1
  112. # return true if x is a prefix of xjunk, given that prefixes are only
  113. # valid at . delimiters
  114. # if !do_if0, skip the whole thing - this is here just to make caller simpler
  115. proc is_prefix {do_if0 x xjunk} {
  116.     if 0!=$do_if0 {return 0}
  117.     set split [split $xjunk .]
  118.     for {set i [expr [llength $split]-1]} {$i>=0} {incr i -1} {
  119.         if [string match $x [join [lrange $split 0 $i] .]] {return 1}
  120.     }
  121.     return 0
  122. }
  123.  
  124. # get domainname.  Unfortunately, on some systems, domainname(1)
  125. # returns NIS domainname which is not the internet domainname.
  126. proc domainname {} {
  127.     # open pops stack upon failure
  128.     set rc [catch {open /etc/resolv.conf r} file]
  129.     if {$rc==0} {
  130.         while {-1!=[gets $file buf]} {
  131.             if 1==[scan $buf "domain %s" name] {
  132.                 close $file
  133.                 return $name
  134.             }
  135.         }
  136.         close $file
  137.     }
  138.  
  139.     # fall back to using domainname
  140.     if {0==[catch {exec domainname} name]} {return $name}
  141.  
  142.     error "could not figure out domainname"
  143. }
  144.  
  145. if $user_number==1 {
  146.     if $noproc==0 {
  147.         if [llength $argv]>1 {
  148.             set pid [eval spawn [lrange $argv 1 end]]
  149.         } else {
  150.             # if running as CGI, shell may not be set!
  151.             set shell /bin/sh
  152.             catch {set shell $env(SHELL)}
  153.             set pid [spawn $shell]
  154.         }
  155.         set shell $spawn_id
  156.     }
  157.  
  158.     # is user2 remote?
  159.     regexp (\[^@\]*)@*(.*) $user ignore tmp host
  160.     set user $tmp
  161.     if ![string match $host ""] {
  162.         set h_rc [catch {exec hostname}    hostname]
  163.         set d_rc [catch domainname     domainname]
  164.  
  165.         if {![is_prefix $h_rc $host $hostname]
  166.          && ![is_prefix $d_rc $host $hostname.$domainname]} {
  167.             set user2_islocal 0
  168.         }
  169.     }
  170.  
  171.     if !$user2_islocal {
  172.         if $verbose {send_user "connecting to $host\n"}
  173.  
  174.         if ![info exists proxy] {
  175.             proc whoami {} {
  176.                 global env
  177.                 if [info exists env(USER)] {return $env(USER)}
  178.                 if [info exists env(LOGNAME)] {return $env(LOGNAME)}
  179.                 if ![catch {exec whoami} user] {return $user}
  180.                 if ![catch {exec logname} user] {return $user}
  181.                 # error "can't figure out who you are!"
  182.             }
  183.             set proxy [whoami]
  184.         }
  185.         spawn rlogin $host -l $proxy -8
  186.         set userin $spawn_id
  187.         set userout $spawn_id
  188.  
  189.         catch {set prompt $env(EXPECT_PROMPT)}
  190.  
  191.         set timeout 120
  192.         expect {
  193.             assword: {
  194.                 stty -echo
  195.                 send_user "password (for $proxy) on $host: "
  196.                 set old_timeout $timeout; set timeout -1
  197.                 expect_user -re "(.*)\n"
  198.                 send_user "\n"
  199.                 set timeout $old_timeout
  200.                 send "$expect_out(1,string)\r"
  201.                 # bother resetting echo?
  202.                 exp_continue
  203.             } incorrect* {
  204.                 send_user "invalid password or account\n"
  205.                 exit
  206.             } "TERM = *) " {
  207.                 send "\r"
  208.                 exp_continue
  209.             } timeout {
  210.                 send_user "connection to $host timed out\n"
  211.                 exit
  212.             } eof {
  213.                 send_user "connection to host failed: $expect_out(buffer)"
  214.                 exit
  215.             } -re $prompt
  216.         }
  217.         if $verbose {send_user "starting kibitz on $host\n"}
  218.         # the kill protects user1 from receiving user3's
  219.         # prompt if user2 exits via expect's exit.
  220.         send "$kibitz $kibitz_flags -r $user;kill -9 $$\r"
  221.  
  222.         expect {
  223.             -re "kibitz $kibitz_flags -r $user.*KRUN" {}
  224.             -re "kibitz $kibitz_flags -r $user.*(kibitz\[^\r\]*)\r" {
  225.                 send_user "unable to start kibitz on $host: \"$expect_out(1,string)\"\n"
  226.                 send_user "try rlogin by hand followed by \"kibitz $user\"\n"
  227.                 exit
  228.             }
  229.             timeout {
  230.                 send_user "unable to start kibitz on $host: "
  231.                 set expect_out(buffer) "timed out"
  232.                 set timeout 0; expect -re .+
  233.                 send_user $expect_out(buffer)
  234.                 exit
  235.             }
  236.         }
  237.         expect {
  238.             -re ".*\n" {
  239.                 # pass back diagnostics
  240.                 # should really strip out extra cr
  241.                 send_user $expect_out(buffer)
  242.                 exp_continue
  243.             }
  244.             KABORT exit
  245.             default exit
  246.             KDATA
  247.         }
  248.     }
  249. }
  250.  
  251. if $user_number==2 {
  252.     set pid [string trimleft $user -]
  253. }
  254.  
  255. set local_io [expr ($user_number==3)||$user2_islocal]
  256. if $local_io||($user_number==2) {
  257.     if 0==[info exists pid] {set pid [pid]}
  258.  
  259.     set userinfile /tmp/exp0.$pid
  260.     set useroutfile /tmp/exp1.$pid
  261. }
  262.  
  263. proc prompt1 {} {
  264.     return "kibitz[info level].[history nextid]> "
  265. }
  266.  
  267. set esc_match {}
  268. if {$allow_escape} {
  269.    set esc_match {
  270.       $escape_char {
  271.     send_user "\nto exit kibitz, enter: exit\n"
  272.     send_user "to suspend kibitz, press appropriate job control sequence\n"
  273.     send_user "to return to kibitzing, enter: return\n"
  274.     interpreter
  275.     send_user "returning to kibitz\n"
  276.       }
  277.    }
  278. }
  279.  
  280. proc prompt1 {} {
  281.     return "kibitz[info level].[history nextid]> "
  282. }
  283.  
  284. set timeout -1
  285.  
  286. # kibitzer executes following code
  287. if $user_number==2 {
  288.     # for readability, swap variables
  289.     set tmp $userinfile
  290.     set userinfile $useroutfile
  291.     set useroutfile $tmp
  292.  
  293.     if ![file readable $userinfile] {
  294.         send_user "Eh?  No one is asking you to kibitz.\n"
  295.         exit -1
  296.     }
  297.      spawn -open [open "|cat $catflags < $userinfile" "r"]
  298.     set userin $spawn_id
  299.  
  300.     spawn -open [open $useroutfile w]
  301.     set userout $spawn_id
  302.     # open will hang until other user's cat starts
  303.  
  304.     stty -echo raw
  305.     if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
  306.  
  307.     # While user is reading message, try to delete other fifo
  308.     catch {exec rm -f $userinfile}
  309.  
  310.     eval interact $esc_match \
  311.         -output $userout \
  312.         -input $userin
  313.  
  314.     exit
  315. }
  316.  
  317. # only user_numbers 1 and 3 execute remaining code
  318.  
  319. proc abort {} {
  320.     global user_number
  321.  
  322.     # KABORT tells user_number 1 that user_number 3 has run into problems
  323.     # and is exiting, and diagnostics have been returned already
  324.     if $user_number==3 {send_user KABORT}
  325.     exit
  326. }
  327.  
  328. if $local_io {
  329.     proc mkfifo {f} {
  330.     if 0==[catch {exec mkfifo $f}] return        ;# POSIX
  331.     if 0==[catch {exec mknod $f p}] return
  332.     # some systems put mknod in wierd places
  333.     if 0==[catch {exec /usr/etc/mknod $f p}] return    ;# Sun
  334.     if 0==[catch {exec /etc/mknod $f p}] return    ;# AIX, Cray
  335.     puts "Couldn't figure out how to make a fifo - where is mknod?"
  336.     abort
  337.     }
  338.  
  339.     proc rmfifos {} {
  340.     global userinfile useroutfile
  341.     catch {exec rm -f $userinfile $useroutfile}
  342.     }
  343.  
  344.     trap {rmfifos; exit} {SIGINT SIGQUIT SIGTERM}
  345.  
  346.     # create 2 fifos to communicate with other user
  347.     mkfifo $userinfile
  348.     mkfifo $useroutfile
  349.     # make sure other user can access despite umask
  350.     exec chmod 666 $userinfile $useroutfile
  351.  
  352.     if $verbose {send_user "asking $user to type:  kibitz -$pid\n"}
  353.  
  354.     # can't use exec since write insists on being run from a tty!
  355.     set rc [catch {
  356.            system echo "Can we talk?  Run: \"kibitz -$pid\"" | \
  357.             /bin/write $user $tty
  358.         }
  359.     ]
  360.     if $rc {rmfifos;abort}
  361.  
  362.     spawn -open [open $useroutfile w]
  363.     set userout $spawn_id
  364.     # open will hang until other user's cat starts
  365.  
  366.     spawn -open [open "|cat $catflags < $userinfile" "r"]
  367.     set userin $spawn_id
  368.     catch {exec rm $userinfile}
  369. }
  370.  
  371. stty -echo raw
  372.  
  373. if $user_number==3 {
  374.     send_user "KDATA"    ;# this tells user_number 1 to send data
  375.  
  376.     interact {
  377.         -output $userout
  378.         -input $userin eof {
  379.             wait -i $userin
  380.             return -tcl
  381.         } -output $user_spawn_id 
  382.     }
  383. } else {
  384.     if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
  385.  
  386.     if $noproc {
  387.         interact {
  388.             -output $userout
  389.             -input $userin eof {wait -i $userin; return}
  390.             -output $user_spawn_id
  391.         }
  392.     } else {
  393.         eval interact $esc_match {
  394.             -output $shell \
  395.             -input $userin eof {
  396.                 wait -i $userin
  397.                 close -i $shell
  398.                 return
  399.             } -output $shell \
  400.             -input $shell -output "$user_spawn_id $userout"
  401.         }
  402.         wait -i $shell
  403.     }
  404. }
  405.  
  406. if $local_io rmfifos
  407.